home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / packet / terminal / kam510 / kam-io.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-12-02  |  17.7 KB  |  681 lines

  1. { global declarations }
  2.  
  3. const
  4.   UART_THR = $00;    { offset from base of UART Registers for IBM PC }
  5.   UART_RBR = $00;
  6.   UART_IER = $01;
  7.   UART_IIR = $02;
  8.   UART_LCR = $03;
  9.   UART_MCR = $04;
  10.   UART_LSR = $05;
  11.   UART_MSR = $06;
  12.  
  13.   I8088_IMR = $21;   { port address of the Interrupt Mask Register }
  14.  
  15.   COM1_Base = $03F8;  { port addresses for the UART }
  16.   COM2_Base = $02F8;
  17.  
  18.   COM1_Irq = 4;  { Interrupt line for the UART }
  19.   COM2_Irq = 3;
  20.  
  21.   Async_Buffer_Max = $0FFF;
  22.  
  23. var
  24.  
  25.   OldInterruptSegment,
  26.   OldInterruptOffset : integer;
  27.  
  28.   Async_Buffer       : Array[0..Async_Buffer_Max] of char;
  29.   Async_Open_Flag    : Boolean;   { true if Open but no Close }
  30.   Async_Port         : Integer;   { current Open port number (1 or 2) }
  31.   Async_Base         : Integer;   { base for current open port }
  32.   Async_Irq          : Integer;   { irq for current open port }
  33.  
  34.   Async_Buffer_Overflow : Boolean;  { True if buffer overflow has happened }
  35.   Async_MaxBufferUsed   : Integer;
  36.  
  37.     { Async_Buffer is empty if Head = Tail }
  38.   Async_Buffer_Head  : Integer;   { Locn in Async_Buffer to put next char }
  39.   Async_Buffer_Tail  : Integer;   { Locn in Async_Buffer to get next char }
  40.   Async_Buffer_NewTail : Integer;
  41.  
  42. const
  43.   Async_Num_Bauds = 8;
  44.   Async_Baud_Table : array [1..Async_Num_Bauds] of record
  45.                                                      Baud, Bits : integer
  46.                                                    end
  47.                    = ((Baud:110;  Bits:$00),
  48.                       (Baud:150;  Bits:$20),
  49.                       (Baud:300;  Bits:$40),
  50.                       (Baud:600;  Bits:$60),
  51.                       (Baud:1200; Bits:$80),
  52.                       (Baud:2400; Bits:$A0),
  53.                       (Baud:4800; Bits:$C0),
  54.                       (Baud:9600; Bits:$E0));
  55.  
  56. {----------------------------------------------------------------------}
  57. { Issue Interrupt $14 to initialize the UART                           }
  58. { See the IBM PC Technical Reference Manual for the format of ComParm  }
  59. {----------------------------------------------------------------------}
  60.  
  61. procedure BIOS_RS232_Init(ComPort, ComParm : Integer);
  62. var
  63.   Regs : Registers;
  64. begin
  65.   with Regs do
  66.     begin
  67.       ax := ComParm AND $00FF;  { AH=0; AL=ComParm }
  68.       dx := ComPort;
  69.       Intr($14, Regs)
  70.     end
  71. end; { BIOS_RS232_Init }
  72.  
  73. {----------------------------------------------------------------------}
  74. { call DOS to set an interrupt vector                                  }
  75. {----------------------------------------------------------------------}
  76. procedure GetInterruptVector(v : integer);
  77. var Regs : Registers;
  78. begin
  79.   with Regs do
  80.     begin
  81.       ax := $3500 + (v AND $00FF);
  82.       MsDos(Regs);
  83.       OldInterruptSegment := bx;
  84.       OldInterruptOffset  := es;
  85.     end;
  86. end;
  87.  
  88. procedure DOS_Set_Intrpt(v, s, o : integer);
  89. var
  90.   Regs : Registers;
  91. begin
  92.   with Regs do
  93.     begin
  94.       ax := $2500 + (v AND $00FF);
  95.       ds := s;
  96.       dx := o;
  97.       MsDos(Regs)
  98.     end
  99. end; { DOS_Set_Intrpt }
  100.  
  101. procedure RestoreInterruptVector(v : integer);
  102. begin
  103.   DOS_Set_Intrpt(v, OldInterruptSegment, OldInterruptOffset);
  104. end;
  105.  
  106. {----------------------------------------------------------------------}
  107. {                                                                      }
  108. {  ASYNCISR.INC - Interrupt Service Routine                            }
  109. { Invoked when the UART has received a byte of data from the           }
  110. {  communication line                                                  }
  111. {                                                                      }
  112. {----------------------------------------------------------------------}
  113.  
  114. procedure Async_Isr;
  115. interrupt;
  116. begin
  117.  
  118.   Inline(
  119.     $FB/                           { STI }
  120.       { get the incoming character }
  121.       { Async_Buffer[Async_Buffer_Head] := Chr(Port[UART_RBR + Async_Base]); }
  122.     $8B/$16/Async_Base/            { MOV DX,Async_Base }
  123.     $EC/                           { IN AL,DX }
  124.     $8B/$1E/Async_Buffer_Head/     { MOV BX,Async_Buffer_Head }
  125.     $88/$87/Async_Buffer/          { MOV Async_Buffer[BX],AL }
  126.       { Async_Buffer_NewHead := Async_Buffer_Head + 1; }
  127.     $43/                           { INC BX }
  128.       { if Async_Buffer_NewHead > Async_Buffer_Max then
  129.           Async_Buffer_NewHead := 0; }
  130.     $81/$FB/Async_Buffer_Max/      { CMP BX,Async_Buffer_Max }
  131.     $7E/$02/                       { JLE L001 }
  132.     $33/$DB/                       { XOR BX,BX }
  133.       { if Async_Buffer_NewHead = Async_Buffer_Tail then
  134.           Async_Buffer_Overflow := TRUE
  135.         else }
  136. {L001:}
  137.     $3B/$1E/Async_Buffer_Tail/     { CMP BX,Async_Buffer_Tail }
  138.     $75/$08/                       { JNE L002 }
  139.     $C6/$06/Async_Buffer_Overflow/$01/ { MOV Async_Buffer_Overflow,1 }
  140.     $90/                           { NOP }
  141.     $EB/$04/                       { JMP SHORT L003 }
  142.       { Async_Buffer_Head := Async_Buffer_NewHead }
  143. {L002:}
  144.     $89/$1E/Async_Buffer_Head/     { MOV Async_Buffer_Head,BX }
  145. {L003:}
  146.       { disable interrupts }
  147.     $FA/                           { CLI }
  148.       { Port[$20] := $20; }  { use non-specific EOI }
  149.     $B0/$20/                       { MOV AL,20h }
  150.     $E6/$20 )                      { OUT 20h,AL }
  151. end; { Async_Isr }
  152. {----------------------------------------------------------------------}
  153. { Async_Close                                                          }
  154. { Turn off the COM port interrupts.                                    }
  155. { reset the interrupt system when UART interrupts no longer needed     }
  156. {----------------------------------------------------------------------}
  157.  
  158. procedure Async_Close;
  159. var
  160.   i, m : Integer;
  161. begin
  162.   if Async_Open_Flag then          { disable the IRQ on the 8259 }
  163.     begin
  164.       Inline($FA);                 { disable interrupts }
  165.       i := Port[I8088_IMR];        { get the interrupt mask register }
  166.       m := 1 shl Async_Irq;        { set mask to turn off interrupt }
  167.       Port[I8088_IMR] := i OR m;
  168.                                    { disable the 8250 data ready interrupt }
  169.       Port[UART_IER + Async_Base] := 0;
  170.                                    { disable OUT2 on the 8250 }
  171.       Port[UART_MCR + Async_Base] := 0;
  172.       RestoreInterruptVector(Async_Irq + 8);
  173.       Inline($FB);                 { enable interrupts }
  174.                                    { restore old interrupt vector }
  175.       Async_Open_Flag := FALSE     { so we know the port is closed }
  176.     end
  177. end; { Async_Close }
  178.  
  179.  
  180. {----------------------------------------------------------------------}
  181. {      Async_Open(Port, Baud : Integer;                                }
  182. {               Parity : Char;                                         }
  183. {               WordSize, StpBits : Integer) : Boolean                 }
  184. {      Sets up interrupt vector, initialies the COM port for           }
  185. {      processing, sets pointers to the buffer.  Returns FALSE if COM  }
  186. {      port not installed.                                             }
  187. {----------------------------------------------------------------------}
  188.  
  189. function Async_Open(ComPort       : Integer;
  190.                     BaudRate      : Integer;
  191.                     Parity        : Char;
  192.                     WordSize      : Integer;
  193.                     StopBits      : Integer): boolean;
  194. var
  195.   ComParm : Integer;
  196.   i, m : Integer;
  197. begin
  198.   Async_Open_Flag := FALSE;
  199.   if Async_Open_Flag then Async_Close;
  200.  
  201.   if ComPort = 2 then
  202.     begin
  203.       Async_Port := 2;
  204.       Async_Base := COM2_Base;
  205.       Async_Irq  := COM2_Irq
  206.     end
  207.   else
  208.     begin
  209.       Async_Port := 1;  { default to COM1 }
  210.       Async_Base := COM1_Base;
  211.       Async_Irq  := COM1_Irq
  212.     end;
  213.  
  214.   GetInterruptVector(Async_Irq + 8);
  215.  
  216.   if (Port[UART_IIR + Async_Base] AND $00F8) <> 0
  217.   then
  218.     Async_Open := FALSE
  219.   else
  220.     begin
  221.  
  222.       Async_Buffer_Head := 0;
  223.       Async_Buffer_Tail := 0;
  224.       Async_Buffer_Overflow := FALSE;
  225.  
  226.   { Build the ComParm for RS232_Init }
  227.   { See Technical Reference Manual for description }
  228.  
  229.       ComParm := $0000;
  230.  
  231.   { Set up the bits for the baud rate }
  232.       i := 0;
  233.       repeat
  234.         i := i + 1
  235.       until (Async_Baud_Table[i].Baud = BaudRate) OR (i = Async_Num_Bauds);
  236.       ComParm := ComParm OR Async_Baud_Table[i].Bits;
  237.  
  238.       if Parity in ['E', 'e'] then ComParm := ComParm OR $0018
  239.       else if Parity in ['O', 'o'] then ComParm := ComParm OR $0008
  240.       else ComParm := ComParm OR $0000;  { default to No parity }
  241.  
  242.       if WordSize = 7
  243.         then ComParm := ComParm OR $0002
  244.         else ComParm := ComParm OR $0003;  { default to 8 data bits }
  245.  
  246.       if StopBits = 2
  247.         then ComParm := ComParm OR $0004
  248.         else ComParm := ComParm OR $0000;  { default to 1 stop bit }
  249.  
  250.   { use the BIOS COM port initialization routine to save typing the code }
  251.       BIOS_RS232_Init(Async_Port - 1, ComParm);
  252.  
  253.       DOS_Set_Intrpt(Async_Irq + 8, CSeg, Ofs(Async_Isr));
  254.  
  255.   { read the RBR and reset any possible pending error conditions }
  256.   { first turn off the Divisor Access Latch Bit to allow access to RBR, etc. }
  257.  
  258.       Inline($FA);  { disable interrupts }
  259.  
  260.       Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] AND $7F;
  261.   { read the Line Status Register to reset any errors it indicates }
  262.       i := Port[UART_LSR + Async_Base];
  263.   { read the Receiver Buffer Register in case it contains a character }
  264.       i := Port[UART_RBR + Async_Base];
  265.  
  266.   { enable the irq on the 8259 controller }
  267.       i := Port[I8088_IMR];  { get the interrupt mask register }
  268.       m := (1 shl Async_Irq) XOR $00FF;
  269.       Port[I8088_IMR] := i AND m;
  270.  
  271.   { enable the data ready interrupt on the 8250 }
  272.       Port[UART_IER + Async_Base] := $01; { enable data ready interrupt }
  273.  
  274.   { enable OUT2 on 8250 }
  275.       i := Port[UART_MCR + Async_Base];
  276.       Port[UART_MCR + Async_Base] := i OR $08;
  277.  
  278.       Inline($FB); { enable interrupts }
  279.       Async_Open_Flag := TRUE;  { bug fix by Scott Herr }
  280.       Async_Open := TRUE;
  281.   end;
  282. end; { Async_Open }
  283.  
  284. {----------------------------------------------------------------------}
  285. {      Transmits the character.                                        }
  286. {----------------------------------------------------------------------}
  287.  
  288. procedure kam_out(C : char);
  289. var
  290.   i, m, counter : Integer;
  291. begin
  292.   { turn on OUT2, DTR, and RTS }
  293.     Port[UART_MCR + Async_Base] := $0B;  { wait for CTS }
  294.     while ((Port[UART_MSR + Async_Base] AND $10) = 0)  do ;
  295.  { wait for Transmit Hold Register Empty (THRE) }
  296.     while ((Port[UART_LSR + Async_Base] AND $20) = 0) do ;
  297.  { send the character }
  298.     Inline($FA); { disable interrupts }
  299.     Port[UART_THR + Async_Base] := Ord(C);
  300.     Inline($FB) { enable interrupts }
  301. end;
  302.  
  303. {----------------------------------------------------------------------}
  304. {      Remove Character From Interrupt Driven Buffer                   }
  305. {----------------------------------------------------------------------}
  306.  
  307. function kam_in: char;
  308. begin
  309.   Inline($FA);                           { disable interrupts }
  310.   kam_in := Async_Buffer[Async_Buffer_Tail];
  311.   Async_Buffer_Tail := (Async_Buffer_Tail + 1) AND Async_Buffer_Max;
  312.   Inline($FB);                           { enable interrupts }
  313. end;
  314.  
  315. {----------------------------------------------------------------------}
  316. {      If a character is available, returns TRUE                       }
  317. {----------------------------------------------------------------------}
  318.  
  319. function char_ready:boolean;
  320. begin
  321.   char_ready := (Async_Buffer_Head <> Async_Buffer_Tail);
  322. end;
  323.  
  324. var _bufchr : char;
  325.  
  326. procedure clear_buffer;
  327. begin
  328.   repeat
  329.     while (char_ready) do
  330.     begin
  331.       _bufchr := kam_in;
  332.       delay(2);
  333.     end;
  334.     delay(50);
  335.   until NOT char_ready;
  336. end;
  337.  
  338. procedure Cmd(s : msg_type);
  339. var i : integer;
  340. begin
  341.   for i := 1 to length(s) do
  342.     kam_out(s[i]);
  343. end;
  344.  
  345. procedure CmdCR(s : msg_type);
  346. begin
  347.   Cmd(s);
  348.   if (s = ^C) then delay(200);
  349.   Cmd(#13);
  350. end;
  351.  
  352. procedure CmdClr(s : msg_type);
  353. begin
  354.   Cmd(s);
  355.   clear_buffer;
  356. end;
  357.  
  358. procedure CmdCRClr(s : msg_type);
  359. begin
  360.   CmdCR(s);
  361.   clear_buffer;
  362. end;
  363.  
  364. procedure wait_for_colon;
  365. begin
  366.   _bufchr := ' ';
  367.   repeat
  368.     if (char_ready) then
  369.       _bufchr := kam_in;
  370.   until (_bufchr = ':');
  371. end;
  372.  
  373. procedure CmdColon(s : msg_type);
  374. begin
  375.   clear_buffer;
  376.   Cmd(s);
  377.   wait_for_colon;
  378. end;
  379.  
  380. procedure ForceCmd;
  381. begin
  382.   if (mode = PACKET) then
  383.   begin
  384.     cmd(^C);
  385.     delay(200);
  386.   end
  387.   else
  388.     CmdColon(^C'X');
  389. end;
  390.  
  391. procedure CmdCRColon(s : msg_type);
  392. begin
  393.   CmdColon(s + #13);
  394. end;
  395.  
  396. procedure xmt_mode;
  397. begin
  398.   if mode in [CW,RTTY,ASCII,AMTOR] then
  399.   begin
  400.     xmt_ON := TRUE;
  401.     CmdClr(^C'T');
  402.     case mode of
  403.       CW : ;
  404.       RTTY, ASCII : if xmt_on_delay > 0 then
  405.                       delay(xmt_on_delay * 100);
  406.     end;
  407.   end;
  408. end;
  409.  
  410. procedure cw_status;
  411. var  status_str : string[7];
  412.      i : integer;
  413. begin
  414.   Cmd(^C'R');
  415.   status_str := '        ';
  416.   repeat
  417.     for i := 1 to 6 do
  418.       status_str[i] := status_str[i + 1];
  419.     repeat until char_ready;
  420.     status_str[7] := kam_in;
  421.   until (status_str[1] = '-');
  422.   if (status_str[7] = '-') then
  423.     rcv_wpm := copy(status_str,5,2);
  424. end;
  425.  
  426. procedure rcv_stat;
  427. begin
  428.   if mode in [CW,RTTY,ASCII,AMTOR] then
  429.   begin
  430.     case mode of
  431.       ASCII,
  432.       RTTY,
  433.       AMTOR : CmdClr(^C'R');
  434.       CW    : cw_status;
  435.     end;
  436.   end;
  437. end;
  438.  
  439. procedure rcv_mode;
  440. begin
  441.   if mode in [CW,RTTY,ASCII,AMTOR] then
  442.   begin
  443.     xmt_ON := FALSE;
  444.     rcv_stat;
  445.   end;
  446. end;
  447.  
  448. procedure mod_rtty_invert;
  449. begin
  450.   CmdClr(^C'R');
  451.   CmdClr(^C'I');
  452.   invert := NOT invert;
  453.   if xmt_ON then xmt_mode;
  454. end;
  455.  
  456. procedure set_rtty_shift;
  457. begin
  458.   CmdClr(^C'R');
  459.   CmdClr(^C'S');
  460.   if xmt_on then xmt_mode;
  461. end;
  462.  
  463. procedure cw_mode;
  464. begin
  465.   ForceCmd;
  466.   mode := CW;
  467.   CmdCRColon('E OFF');
  468.   CmdCRColon('XM ON');
  469.   CmdCRClr('CW ' + xmt_wpm);
  470.   cw_status;
  471.   state := receive;
  472. end;
  473.  
  474. procedure kam_xmt_wpm;
  475. begin
  476.   cw_mode;
  477.   if xmt_ON then
  478.     CmdClr(^C'T');
  479. end;
  480.  
  481. procedure set_rtty_baud;
  482. begin
  483.   ForceCmd;
  484.   CmdCRColon('RB ' + baud_rate[baud]);
  485.   CmdCRClr('R');
  486.   state := receive;
  487. end;
  488.  
  489. procedure rtty_mode;
  490. begin
  491.   ForceCmd;
  492.   mode := RTTY;
  493.   baud := 0;
  494.   CmdCRColon('E OFF');
  495.   CmdCRColon('XM ON');
  496.   CmdCRColon('MARK 2125');
  497.   CmdCRColon('SPACE 2295');
  498.   CmdCRColon('INVERT OFF');
  499.   CmdCRColon('CRAdd ON');
  500.   CmdCRColon('LF ON');
  501.   CmdCRColon('DIDdle ON');
  502.   CmdCRColon('SH ' + rtty_shift[shift]);
  503.   CmdCRColon('RB ' + baud_rate[baud]);
  504.   CmdCRClr('R');
  505.   state := receive;
  506. end;
  507.  
  508. procedure ascii_mode;
  509. begin
  510.   ForceCmd;
  511.   mode := ASCII;
  512.   baud := 5;
  513.   CmdCRColon('E OFF');
  514.   CmdCRColon('XM ON');
  515.   CmdCRColon('MARK 2125');
  516.   CmdCRColon('SPACE 2295');
  517.   CmdCRColon('ASCB ' + baud_rate[baud] );
  518.   shift := 0;
  519.   CmdCRColon('SH ' + rtty_shift[shift]);
  520.   CmdCRColon('INVERT OFF');
  521.   CmdCRColon('CRAdd ON');
  522.   CmdCRColon('LF ON');
  523.   CmdCRClr('A');
  524.   state := receive;
  525. end;
  526.  
  527. procedure packet_mode;
  528. begin
  529.   ForceCmd;
  530.   mode := PACKET;
  531.   CmdCRColon('E ON');
  532.   CmdCRColon('XM OFF');
  533.   CmdCRColon('MARK '+packet_mark);
  534.   CmdCRColon('SPACE '+packet_space);
  535.   shift := 0;
  536.   CmdCRColon('SH '+ rtty_shift[shift]);
  537.   CmdCRColon(SW_VHF+'A');
  538.   CmdCR('');
  539.   band := VHF;
  540.   state := transceive;
  541. end;
  542.  
  543. procedure HF_Packet;
  544. begin
  545.   ForceCmd;
  546.   CmdCRColon(SW_HF+'A');
  547.   CmdCR('');
  548.   band := HF;
  549. end;
  550.  
  551. procedure VHF_Packet;
  552. begin
  553.   ForceCmd;
  554.   CmdCRColon(SW_VHF+'A');
  555.   CmdCR('');
  556.   band := VHF;
  557. end;
  558.  
  559. procedure AmtorAB(S: string);
  560. begin
  561.   ForceCmd;
  562.   mode := AMTOR;
  563.   CmdCRColon('E OFF');
  564.   CmdCRColon('XM ON');
  565.   if S = '' then begin
  566.                    CmdCRClr('AM');
  567.                    AmtorMode := AB;
  568.                    state := receive;
  569.                  end
  570.             else begin
  571.                    CmdCRClr('AM '+SELCALL);
  572.                    state := transmit;
  573.                    AmtorMode := CALL;
  574.                  end;
  575.   band := HF;
  576. end;
  577.  
  578. procedure AmtorListen;
  579. begin
  580.   ForceCmd;
  581.   mode := AMTOR;
  582.   CmdCRColon('E OFF');
  583.   CmdCRColon('XM ON');
  584.   shift := 0;
  585.   CmdCRColon('SH '+rtty_shift[shift]);
  586.   CmdCRClr('L');
  587.   AmtorMode := L;
  588.   state := receive;
  589.   band := HF;
  590. end;
  591.  
  592. procedure AmtorFEC;
  593. begin
  594.   ForceCmd;
  595.   mode := AMTOR;
  596.   CmdCRColon('E OFF');
  597.   CmdCRColon('XM ON');
  598.   CmdCRClr('FEC');
  599.   AmtorMode := FEC;
  600.   state := receive;
  601.   band := HF;
  602.  end;
  603.  
  604. procedure packet_connect;
  605. begin
  606.   ForceCmd;
  607.   CmdCR('C ' + PKCall);
  608. end;
  609.  
  610. procedure packet_disconnect;
  611. begin
  612.   ForceCmd;
  613.   CmdCR('D');
  614. end;
  615.  
  616. procedure PacketID;
  617. begin
  618.   ForceCmd;
  619.   delay(200);
  620.   CmdCRColon('I');
  621. end;
  622.  
  623. procedure new_mode;
  624. begin
  625.   save_screen;
  626.   aux_color;
  627.   window(35,8,45,16);
  628.   clrscr;
  629.   writeln;
  630.   writeln(' 1> AMTOR');
  631.   writeln(' 2> ASCII');
  632.   writeln(' 3> CW');
  633.   writeln(' 4> PACKET');
  634.   writeln(' 5> RTTY');
  635.   writeln;
  636.   write  (' select..');
  637.   repeat key := readkey until key in ['1'..'5'];
  638.   write(key);
  639.   window(1,1,80,25);
  640.   restore_screen;
  641.   if (mode = PACKET) then packet_disconnect;
  642.   case key of
  643.     '1' : AmtorListen;
  644.     '2' : ascii_mode;
  645.     '3' : cw_mode;
  646.     '4' : packet_mode;
  647.     '5' : rtty_mode;
  648.   end;
  649. end;
  650.  
  651. procedure init_interface;
  652. begin
  653.   if (Async_Open(xmt_port, kam_baud_rate, 'N', 8, 1) = FALSE) then
  654.   begin
  655.     restore_entry_screen;
  656.     Writeln('COM',xmt_port:1,' not installed.');
  657.     halt;
  658.   end;
  659.   writeln('Initializing KAM interface');
  660.   mode := PACKET;
  661.   CmdCRColon('XOFF 0');
  662.   CmdCRColon('XON 0');
  663.   packet_mode;
  664. end;
  665.  
  666. procedure reset_kam;
  667. begin
  668.   case mode of
  669.     CW, RTTY, ASCII, AMTOR : CmdColon(^C'X');
  670.     PACKET : begin
  671.                CmdCRColon('MARK 2100');
  672.                CmdCRColon('SPACE 2300');
  673.                CmdCRColon('8BITCONV ON');
  674.                CmdCRClr(SW_VHF+'A');
  675.                CmdCR('');
  676.              end;
  677.   end;
  678.   Async_close;
  679. end;
  680.  
  681.